/**
    @project {
        "templateId": "org.helgoboss.custom",
        "version": "0.1-SNAPSHOT",
        "dependencies": [
            "org.scala-lang:scala-library:2.9.0-1",
            "org.helgoboss:osgi-additions:0.1-SNAPSHOT",
            "org.helgoboss:scala-additions:0.1-SNAPSHOT",
            "org.helgoboss:commandlet-http-provider:0.1-SNAPSHOT",
            "org.helgoboss:commandlet-api:0.1-SNAPSHOT",
            "org.helgoboss:commandlet-manager:0.1-SNAPSHOT",
            "javax.servlet:servlet-api:2.5"
        ]
    }
*/

package org.helgoboss.commandlet_http_provider_ref_impl

import org.osgi.service.http.HttpService
import org.helgoboss.osgi_additions._
import org.helgoboss.commandlet_manager.CommandletManager
import org.helgoboss.commandlet_http_provider.CommandletHttpProvider


private object Activator {
    val ContextPath = "/commandlet/execute"
    private val DefaultPort = 8080
}

class Activator extends CommandletHttpProvider with OsgiContext with OsgiLogging with OsgiServiceWatcher with OsgiProvider with OsgiConsumer {

    import Activator._
    
    whenBundleActive {
        whenServicesPresent[HttpService, CommandletManager] { (httpService, commandletManager) =>
            onStart {
                val servlet = new CommandletProviderServlet(commandletManager = commandletManager, log = log)
                httpService.registerServlet(ContextPath, servlet, null, null)
            }
            this.providesService[CommandletHttpProvider]
            onStop {
                httpService.unregister(ContextPath)
            }
        }
    }
      

    def port = {
        val configuredPort = bundleContext.getProperty("org.osgi.service.http.port")
        if (configuredPort != null) {
            configuredPort.toInt
        } else {
            DefaultPort
        }
    }
    
    def contextPath = ContextPath
}



import org.helgoboss.commandlet._
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}
import java.io._
import org.helgoboss.commandlet_manager.CommandletManager
import org.helgoboss.scala_additions.Logger
import java.util.Locale
import java.text.Format

class CommandletProviderServlet(commandletManager: CommandletManager, log: Logger) extends HttpServlet {

    override def doPost(request: HttpServletRequest, response: HttpServletResponse) {
        doBoth(request, response)
    }
    override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
        doBoth(request, response)
    }
    
    private def doBoth(request: HttpServletRequest, response: HttpServletResponse) {
        /* Extract parameters */
        
        val commandletId = request.getParameter("id")
        val pathToWorkingDirectory = request.getParameter("wd")
        val argParameterValues = {
            val argArray = request.getParameterValues("arg")
            if (argArray == null) {
                Nil
            } else {
                argArray.toList
            }
        }
                                
        require(pathToWorkingDirectory != null)
        require(commandletId != null)
        
        
        /* Define proxy output stream class */
        
        class SafePrintStream(o: OutputStream) extends PrintStream(o, true) {            
            override def close {
                /* Don't close. We close it at the end. */
            }
            override def flush {
                /* If we flush the response output stream, the connection will end. So we just flush the response buffer. */
                response.flushBuffer
            }
        }

        
        
        /* Find responsible commandlet and forward request to it */
          
        val safePrintStream = new SafePrintStream(response.getOutputStream)      
        
        lazy val executionContext = new ExecutionContext {
            lazy val workingDirectory = new File(pathToWorkingDirectory)
            lazy val arguments = argParameterValues
            lazy val inputStream = request.getInputStream
            lazy val outputStream = safePrintStream
        }
        
        try {
            commandletManager.findCommandlet(commandletId) match {
                case Some(commandlet) =>
                    commandlet.execute(executionContext)
                    
                case None =>
                    response.sendError(HttpServletResponse.SC_NOT_FOUND)
            }
        } catch {
            case e: Exception =>
                e.printStackTrace(safePrintStream)
                if (!response.isCommitted)
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)
                throw e
        } finally {
            response.getOutputStream.close
        }
    }
}

